﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LDASharp
{

    public class LDADictionary
    {
        public Dictionary<String, int> word2id;
        public Dictionary<int, String> id2word;


        #region constructors

        public LDADictionary()
        {
            word2id = new Dictionary<String, int>();
            id2word = new Dictionary<int, String>();
        }

        #endregion

        #region get/set methods

        /// <summary>
        /// Get word of a specified id
        /// </summary>
        /// <param name="word"></param>
        /// <returns>Throw a Exception if failed</returns>
        public String GetWord(int id)
        {
            string word;
            if (id2word.TryGetValue(id, out word))
                return word;
            else
                throw new Exception("Get word failed");
        }

        /// <summary>
        /// Get id of a specified word
        /// </summary>
        /// <param name="word"></param>
        /// <returns>Throw a Exception if failed</returns>
        public int GetID(String word)
        {
            int id;
            if (word2id.TryGetValue(word, out id))
                return id;
            else
                throw new Exception("Get id failed");
        }
        #endregion
        #region checking methods

        /// <summary>
        /// Check if this dictionary contains a specified word
        /// </summary>
        /// <param name="word"></param>
        /// <returns></returns>
        public bool Contains(String word)
        {
            return word2id.ContainsKey(word);
        }

        /// <summary>
        /// Check if this dictionary contains a specified id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool Contains(int id)
        {
            return id2word.ContainsKey(id);
        }
        #endregion


        #region manupulating methods

        /// <summary>
        /// Add a word into this dictionary
        /// </summary>
        /// <param name="word"></param>
        /// <returns>the corresponding id</returns>
        public int AddWord(String word)
        {
            if (!Contains(word))
            {
                int id = word2id.Count();

                word2id.Add(word, id);
                id2word.Add(id, word);

                return id;
            }
            else return GetID(word);
        }
        #endregion


        #region I/O methods

        /// <summary>
        /// Read dictionary from file
        /// </summary>
        /// <param name="wordMapFile"></param>
        /// <returns></returns>
        public bool ReadWordMap(String wordMapFile)
        {
            try
            {
                StreamReader reader = new StreamReader(wordMapFile, Encoding.UTF8);
                String line;

                //read the number of words
                line = reader.ReadLine();
                int nwords = int.Parse(line);

                //read map
                for (int i = 0; i < nwords; ++i)
                {
                    line = reader.ReadLine();
                    string[] tknr = line.Split(new char[] { '\t', '\n', '\r' });


                    if (tknr.Count() != 2) continue;

                    string word = tknr[0];
                    string id = tknr[1];
                    int intID = int.Parse(id);

                    id2word.Add(intID, word);
                    word2id.Add(word, intID);
                }

                reader.Close();
                return true;
            }
            catch (Exception e)
            {
                Console.WriteLine("Error while reading dictionary:" + e.Message);
                Console.WriteLine(e.StackTrace);
                return false;
            }
        }

        /// <summary>
        /// Write dictionary to file
        /// </summary>
        /// <param name="wordMapFile"></param>
        /// <returns></returns>
        public bool WriteWordMap(String wordMapFile)
        {
            try
            {
                StreamWriter writer = new StreamWriter(wordMapFile, false, Encoding.UTF8);

                //write number of words
                writer.WriteLine(word2id.Count);

                //write word to id
                foreach (KeyValuePair<string, int> pair in word2id)
                {
                    writer.WriteLine(pair.Key + " " + pair.Value);
                }

                writer.Close();
                return true;
            }
            catch (Exception e)
            {
                Console.WriteLine("Error while writing word map " + e.Message);
                Console.WriteLine(e.StackTrace);
                return false;
            }


        }
        #endregion
    }
}
